using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using JGSY.CMS.LowCode.Platform.Domain.Entities;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;
using JGSY.CMS.LowCode.Platform.Infrastructure.CmsDbContext;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Repositories
{
    /// <summary>
    /// 权限路由映射仓储实现
    /// 提供高效的路由匹配和动态管理功能
    /// </summary>
    public class PermissionRouteMappingRepository : IPermissionRouteMappingRepository
    {
        private readonly LowCodeDbContext _context;
        private readonly ILogger<PermissionRouteMappingRepository> _logger;

        public PermissionRouteMappingRepository(LowCodeDbContext context, ILogger<PermissionRouteMappingRepository> logger)
        {
            _context = context;
            _logger = logger;
        }

        public async Task<IEnumerable<PermissionRouteMapping>> GetActiveAsync()
        {
            return await _context.PermissionRouteMappings
                .AsNoTracking()
                .Where(m => m.IsActive)
                .OrderBy(m => m.Priority)
                .ThenBy(m => m.SortOrder)
                .ThenBy(m => m.Id)
                .ToListAsync();
        }

        public async Task<IEnumerable<PermissionRouteMapping>> GetAllAsync()
        {
            return await _context.PermissionRouteMappings
                .AsNoTracking()
                .OrderBy(m => m.Priority)
                .ThenBy(m => m.SortOrder)
                .ThenBy(m => m.Id)
                .ToListAsync();
        }

        public async Task<PermissionRouteMapping?> GetByIdAsync(long id)
        {
            return await _context.PermissionRouteMappings
                .AsNoTracking()
                .FirstOrDefaultAsync(m => m.Id == id);
        }

        public async Task<PermissionRouteMapping?> FindMatchingAsync(string path, string method)
        {
            var mappings = await GetActiveAsync();
            
            foreach (var mapping in mappings)
            {
                if (IsMatch(path, mapping.Path) && 
                    string.Equals(mapping.Method, method, StringComparison.OrdinalIgnoreCase))
                {
                    return mapping;
                }
            }
            
            return null;
        }

        public async Task<IEnumerable<PermissionRouteMapping>> FindMatchingsAsync(IEnumerable<(string path, string method)> requests)
        {
            var mappings = await GetActiveAsync();
            var results = new List<PermissionRouteMapping>();
            
            foreach (var (path, method) in requests)
            {
                var matching = mappings.FirstOrDefault(m => 
                    IsMatch(path, m.Path) && 
                    string.Equals(m.Method, method, StringComparison.OrdinalIgnoreCase));
                
                if (matching != null)
                {
                    results.Add(matching);
                }
            }
            
            return results;
        }

        public async Task<long> AddAsync(PermissionRouteMapping mapping)
        {
            mapping.CreatedAt = DateTime.UtcNow;
            mapping.UpdatedAt = DateTime.UtcNow;
            
            _context.PermissionRouteMappings.Add(mapping);
            await _context.SaveChangesAsync();
            
            _logger.LogInformation("Added permission route mapping: {Path} {Method} -> {Code}", 
                mapping.Path, mapping.Method, mapping.PermissionCode);
            
            return mapping.Id;
        }

        public async Task UpdateAsync(PermissionRouteMapping mapping)
        {
            mapping.UpdatedAt = DateTime.UtcNow;
            
            _context.PermissionRouteMappings.Update(mapping);
            await _context.SaveChangesAsync();
            
            _logger.LogInformation("Updated permission route mapping: {Id}", mapping.Id);
        }

        public async Task DeleteAsync(long id)
        {
            var mapping = await _context.PermissionRouteMappings.FindAsync(id);
            if (mapping != null)
            {
                _context.PermissionRouteMappings.Remove(mapping);
                await _context.SaveChangesAsync();
                
                _logger.LogInformation("Deleted permission route mapping: {Id}", id);
            }
        }

        public async Task BatchDeleteAsync(IEnumerable<long> ids)
        {
            var mappings = await _context.PermissionRouteMappings
                .Where(m => ids.Contains(m.Id))
                .ToListAsync();
                
            _context.PermissionRouteMappings.RemoveRange(mappings);
            await _context.SaveChangesAsync();
            
            _logger.LogInformation("Batch deleted {Count} permission route mappings", mappings.Count);
        }

        public async Task<IEnumerable<PermissionRouteMapping>> GetByGroupAsync(string group)
        {
            return await _context.PermissionRouteMappings
                .AsNoTracking()
                .Where(m => m.Group == group)
                .OrderBy(m => m.Priority)
                .ThenBy(m => m.SortOrder)
                .ToListAsync();
        }

        public async Task<IEnumerable<string>> GetGroupsAsync()
        {
            return await _context.PermissionRouteMappings
                .AsNoTracking()
                .Where(m => !string.IsNullOrEmpty(m.Group))
                .Select(m => m.Group!)
                .Distinct()
                .OrderBy(g => g)
                .ToListAsync();
        }

        public async Task<bool> HasConflictAsync(string path, string method, long? excludeId = null)
        {
            var query = _context.PermissionRouteMappings
                .Where(m => m.IsActive && m.Path == path && m.Method == method);
                
            if (excludeId.HasValue)
            {
                query = query.Where(m => m.Id != excludeId.Value);
            }
            
            return await query.AnyAsync();
        }

        public async Task<int> BatchImportAsync(IEnumerable<PermissionRouteMapping> mappings, bool replaceExisting = false)
        {
            var importList = mappings.ToList();
            var imported = 0;
            
            foreach (var mapping in importList)
            {
                var existing = await _context.PermissionRouteMappings
                    .FirstOrDefaultAsync(m => m.Path == mapping.Path && m.Method == mapping.Method);
                
                if (existing != null)
                {
                    if (replaceExisting)
                    {
                        existing.PermissionCode = mapping.PermissionCode;
                        existing.Name = mapping.Name;
                        existing.Description = mapping.Description;
                        existing.Priority = mapping.Priority;
                        existing.IsActive = mapping.IsActive;
                        existing.Group = mapping.Group;
                        existing.UpdatedAt = DateTime.UtcNow;
                        existing.UpdatedBy = mapping.UpdatedBy;
                        imported++;
                    }
                }
                else
                {
                    mapping.CreatedAt = DateTime.UtcNow;
                    mapping.UpdatedAt = DateTime.UtcNow;
                    _context.PermissionRouteMappings.Add(mapping);
                    imported++;
                }
            }
            
            await _context.SaveChangesAsync();
            _logger.LogInformation("Batch imported {Count} permission route mappings", imported);
            
            return imported;
        }

        public async Task<string> ExportAsJsonAsync(string? group = null)
        {
            var query = _context.PermissionRouteMappings.AsNoTracking();
            
            if (!string.IsNullOrEmpty(group))
            {
                query = query.Where(m => m.Group == group);
            }
            
            var mappings = await query
                .OrderBy(m => m.Priority)
                .ThenBy(m => m.SortOrder)
                .Select(m => new
                {
                    m.Path,
                    m.Method,
                    m.PermissionCode,
                    m.Name,
                    m.Description,
                    m.Priority,
                    m.IsActive,
                    m.Group
                })
                .ToListAsync();
            
            return JsonSerializer.Serialize(mappings, new JsonSerializerOptions 
            { 
                WriteIndented = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            });
        }

        public async Task<(int total, int active, int groups)> GetStatisticsAsync()
        {
            var total = await _context.PermissionRouteMappings.CountAsync();
            var active = await _context.PermissionRouteMappings.CountAsync(m => m.IsActive);
            var groups = await _context.PermissionRouteMappings
                .Where(m => !string.IsNullOrEmpty(m.Group))
                .Select(m => m.Group!)
                .Distinct()
                .CountAsync();
            
            return (total, active, groups);
        }

        private bool IsMatch(string requestPath, string pattern)
        {
            try
            {
                // 支持 ** 跨段前缀匹配，* 单段匹配
                string regex = Regex.Escape(pattern)
                    .Replace("\\*\\*", ".*")
                    .Replace("\\*", "[^/]+");
                    
                if (!regex.StartsWith("^")) regex = "^" + regex;
                if (!regex.EndsWith("$")) regex += "$";
                
                return Regex.IsMatch(requestPath, regex, RegexOptions.IgnoreCase);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Invalid pattern in route mapping: {Pattern}", pattern);
                return false;
            }
        }
    }
}
